﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace DataProcess.Core.Tools
{

    public class PropertyHelper
    {
        /// <summary>
        /// 根据属性名称获取属性
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="propName">属性名称</param>
        /// <returns></returns>
        public static PropertyInfo GetProp<T>(string propName)
        {
            if (string.IsNullOrEmpty(propName)) throw new Exception("传入的属性名不能为null");
            Type type = typeof(T);
            return GetProp(type, propName);
        }

        /// <summary>
        /// 根据属性名称获取属性
        /// </summary>
        /// <param name="type">实体类型</param>
        /// <param name="propName">实体中的属性名</param>
        /// <returns></returns>
        public static PropertyInfo GetProp(Type type, string propName)
        {
            if (type == null) throw new Exception("传入的Type对象不能为null");
            if (string.IsNullOrEmpty(propName)) throw new Exception("传入的属性名不能为null");
            try
            {
                return type.GetProperty(propName);
            }
            catch
            {
                return type.GetProperty(propName, BindingFlags.DeclaredOnly | BindingFlags.Public |
                           BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
            }
        }

        /// <summary>
        /// 获取属性名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static string GetPropertyName<T>(Expression<Func<T, object>> expr)
        {
            if (expr == null) throw new Exception("传入的表达式对象不能为null");
            var rtn = "";
            if (expr.Body is UnaryExpression ue)
            {
                rtn = ((MemberExpression)ue.Operand).Member.Name;
            }
            else if (expr.Body is MemberExpression me)
            {
                rtn = me.Member.Name;
            }
            else if (expr.Body is ParameterExpression pe)
            {
                rtn = pe.Type.Name;
            }
            return rtn;
        }

        /// <summary>
        /// 获取lambda表达式的属性和值的映射Map
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="expr">表达式</param>
        /// <returns></returns>
        public static Dictionary<string, object> GetPropertyNameValue<T>(Expression<Func<T, T>> expr)
        {
            if (expr == null) throw new Exception("传入的表达式对象不能为null");
            Dictionary<string, object> dic = new Dictionary<string, object>();
            if (expr.Body is MemberInitExpression memberinit && memberinit.Bindings != null)
            {
                foreach (MemberAssignment bind in memberinit.Bindings)
                {
                    var value = (bind.Expression as ConstantExpression)?.Value;
                    if (value != null && bind.Member != null)
                    {
                        if (!dic.ContainsKey(bind.Member.Name))
                        {
                            dic.Add(bind.Member.Name, value);
                        }
                    }
                }
            }
            return dic;
        }

        /// <summary>
        /// 根据特性获取对象中包含该特性的属性的名称
        /// </summary>
        /// <typeparam name="T">要获取属性名称的对象</typeparam>
        /// <param name="attrType">特性类型</param>
        /// <returns></returns>
        public static string GetPropNameByAttribute<T>(Type attrType)
        {
            if (attrType == null) throw new Exception("传入的Type对象不能为null");
            var prop = typeof(T).GetProperties().Where(pi => pi.GetCustomAttributes(attrType, true).Any(attr => attr.GetType().FullName == attrType.FullName)).FirstOrDefault();
            if (prop == null)
            {
                return string.Empty;
            }
            return prop.Name;
        }


        /// <summary>
        /// 获取属性中指定类型的特性
        /// </summary>
        /// <typeparam name="Attr">特性类型</typeparam>
        /// <param name="prop">属性</param>
        /// <returns></returns>
        public static Attr GetAttr<Attr>(PropertyInfo prop) where Attr : Attribute
        {
            if (prop == null) throw new Exception("传入的PropertyInfo对象不能为null");
            return (Attr)prop.GetCustomAttributes(typeof(Attr), true).Single(it => it is Attr);
            //return prop.GetCustomAttribute<Attr>(); .Net 4.5及以上 才支持
        }

        /// <summary>
        /// 获取Enum值
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetEnumValue(PropertyInfo prop, string value)
        {
            if (prop == null) throw new Exception("传入的PropertyInfo对象不能为null");
            foreach (var val in prop.PropertyType.GetEnumValues())
            {
                if (value == Enum.GetName(prop.PropertyType, val))
                {
                    return (int)val;
                }
            };
            return -1;
        }

        /// <summary>
        /// 根据表达式,获取表达式中对应T类型的属性
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static Dictionary<string, Tuple<int, PropertyInfo>> GetPropertyMap(Expression expression)
        {
            Dictionary<string, Tuple<int, PropertyInfo>> map = new Dictionary<string, Tuple<int, PropertyInfo>>();

            if (expression != null)
            {
                if (expression.NodeType == ExpressionType.NewArrayInit)
                {
                    var props = (NewArrayExpression)expression;
                    int index = 0;
                    foreach (var prop in props.Expressions)
                    {
                        PropertyInfo result = GetProperty(prop);
                        if (result != null)
                        {
                            map.Add(result.Name, new Tuple<int, PropertyInfo>(index, result));
                            index++;
                        }
                    }
                }
            }
            return map;
        }


        /// <summary>
        /// 根据表达式,获取表达式中对应T类型的属性名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static List<string> GetPropertyNames<T>(Expression<Func<T, object[]>> expression)
        {
            List<string> list = new List<string>();
            if (expression != null)
            {
                if (expression.Body != null && expression.Body is NewArrayExpression body)
                {
                    foreach (Expression prop in body.Expressions)
                    {
                        if (prop is MemberExpression member)
                        {
                            list.Add(member.Member.Name);
                        }
                    }
                }
            }
            return list;
        }

        /// <summary>
        /// 根据传入的表达式获取对应的属性
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static PropertyInfo GetProperty(Expression expression)
        {
            if (expression.NodeType == ExpressionType.MemberAccess)
            {
                return ((MemberExpression)expression).Member as PropertyInfo;
            }
            else if (expression.NodeType == ExpressionType.Convert)
            {
                Expression expre = ((UnaryExpression)expression).Operand;
                return GetProperty(expre);
            }
            else
            {
                throw new Exception("未实现的类型,请联系开发人员");
            }
        }


        /// <summary>
        /// 获取成员名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static string GetMemberName<T>(Expression<Func<T, object>> expression)
        {
            if (expression != null && expression.Body != null)
            {
                if (expression.Body is MemberExpression body)
                {
                    return body.Member?.Name;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取T类型的所有属性名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<string> GetPropertyNames<T>()
        {
            return typeof(T).GetProperties().Select(it => it.Name).ToList();
        }
    }
}
